#ifndef __Thread_POLL__
#define __Thread_POLL__

#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <unordered_map>
#include <memory>

#include "Task.hpp"
#include "Mutex.hpp"
#include "Cond.hpp"
Mutex_Base mutex_base_;
Cond cond_;

const int defaultnum = 10;

template <class T>
class thread_poll // 线程池
{
    thread_poll(const int num = defaultnum)
        : num_(num)
    {
    }

public:
    const thread_poll& operator=(const thread_poll&) = delete;
    thread_poll(const thread_poll& ) = delete;
    static void *pthread_func(void *args)
    {
        thread_poll *tp = (thread_poll *)args;
        while (1)
        {
            mutex_base_.Lock();
            while (tp->size() == 0)
                cond_.Wait(mutex_base_.GetMutexOriginal());

            T task = tp->pop();
            mutex_base_.Unlock();
            
            task();
        }
        return nullptr;
    }

    ~thread_poll()
    {
    }

    void run()
    {
        for (size_t i = 0; i < num_; i++)
        {
            pthread_t tid;
            std::string thstr = "Process-" + std::to_string(i + 1);
            pthread_create(&tid, nullptr, pthread_func, this);
            thpoll_[tid] = thstr;
        }
    }

    void push(const T &data)
    {
        Mutex m(mutex_base_);
        thq_.push(data);
        cond_.NotifyAll();
    }

    size_t size()
    {
        return thq_.size();
    }

    T pop()
    {
        T ret = thq_.front();
        thq_.pop();
        return ret;
    }

    std::string GetThread_name(pthread_t tid)
    {
        return thpoll_[tid];
    }

    static std::unique_ptr<thread_poll<T>> &GetInstance()
    {
        if (tp_ == nullptr)
        {
            mutex_base_.Lock();
            if (tp_ == nullptr)
            {
                tp_.reset(new thread_poll<T>());
            }
            mutex_base_.Unlock();
        }
        return tp_;
    }

private:
    std::unordered_map<pthread_t, std::string> thpoll_;
    std::queue<T> thq_;
    int num_;

    static std::unique_ptr<thread_poll<T>> tp_;
};

template <class T>
std::unique_ptr<thread_poll<T>> thread_poll<T>::tp_;

#endif